﻿using System;
using System.Windows;
using AgFx;
using Coding4Fun.Phone.Controls.Data;
using DepSoft.Mobile.WP7.FollwIt.Framework;
using DepSoft.Mobile.WP7.FollwIt.Messages;
using DepSoft.Mobile.WP7.FollwIt.Model;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WindowsPhonePostClient;
using WP7Contrib.Services.Navigation;
using WP7Contrib.Services.Settings;
using WP7Contrib.Services.Storage;

namespace DepSoft.Mobile.WP7.FollwIt.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public class MovieSummaryViewModel : ViewModelBaseWp7
    {
        #region Private members
        enum SaveType
        {
            Have,
            Watched,
            Rating
        }
        #endregion

        #region Public properties
        public string PageName
        {
            get
            {
                return "summary";
            }
        }

        public RelayCommand SaveHaveCommand
        {
            get;
            private set;
        }

        public RelayCommand SaveWatchedCommand
        {
            get;
            private set;
        }

        public RelayCommand SaveRatingCommand
        {
            get;
            private set;
        }
        #endregion

        #region Public bindable properties
        #region ApplicationTitle
        /// <summary>
        /// The <see cref="ApplicationTitle" /> property's name.
        /// </summary>
        public const string ApplicationTitlePropertyName = "ApplicationTitle";

        private string _applicationTitle = string.Empty;

        /// <summary>
        /// Gets the ApplicationTitle property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string ApplicationTitle
        {
            get
            {
                return _applicationTitle;
            }

            set
            {
                this.SetPropertyAndNotify(ref _applicationTitle, value, ApplicationTitlePropertyName);
            }
        }
        #endregion

        #region ProgressIndicatorVisible
        /// <summary>
        /// The <see cref="ProgressIndicatorVisible" /> property's name.
        /// </summary>
        public const string ProgressIndicatorVisiblePropertyName = "ProgressIndicatorVisible";

        private bool _progressIndicatorVisible = false;

        /// <summary>
        /// Gets the ProgressIndicatorVisible property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool ProgressIndicatorVisible
        {
            get
            {
                return _progressIndicatorVisible;
            }

            set
            {
                this.SetPropertyAndNotify(ref _progressIndicatorVisible, value, ProgressIndicatorVisiblePropertyName);
            }
        }
        #endregion

        #region ProgressIndicatorText
        /// <summary>
        /// The <see cref="ProgressIndicatorText" /> property's name.
        /// </summary>
        public const string ProgressIndicatorTextPropertyName = "ProgressIndicatorText";

        private string _progressIndicatorText = string.Empty;

        /// <summary>
        /// Gets the ProgressIndicatorText property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string ProgressIndicatorText
        {
            get
            {
                return _progressIndicatorText;
            }

            set
            {
                this.SetPropertyAndNotify(ref _progressIndicatorText, value, ProgressIndicatorTextPropertyName);
            }
        }
        #endregion

        #region MovieSummary
        /// <summary>
        /// The <see cref="MovieSummary" /> property's name.
        /// </summary>
        public const string MovieSummaryPropertyName = "MovieSummary";

        private agfxMovieSummaryViewModel _movieSummary = null;

        /// <summary>
        /// Gets the MovieSummary property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public agfxMovieSummaryViewModel MovieSummary
        {
            get
            {
                return _movieSummary;
            }

            set
            {
                this.SetPropertyAndNotify(ref _movieSummary, value, MovieSummaryPropertyName);
                //if(!ReferenceEquals(_movieSummary, null) && !ReferenceEquals(_movieSummary.MovieDetail, null) && !string.IsNullOrEmpty(_movieSummary.MovieDetail.Translated_title))
                this.ApplicationTitle = _movieSummary.MovieDetail.Translated_title;
            }
        }
        #endregion

        #region CoverVisible
        /// <summary>
        /// The <see cref="CoverVisible" /> property's name.
        /// </summary>
        public const string CoverVisiblePropertyName = "CoverVisible";

        private Visibility _coverVisible = Visibility.Collapsed;

        /// <summary>
        /// Gets the CoverVisible property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public Visibility CoverVisible
        {
            get
            {
                return _coverVisible;
            }

            set
            {
                this.SetPropertyAndNotify(ref _coverVisible, value, CoverVisiblePropertyName);
            }
        }
        #endregion

        #region NoCoverVisible
        /// <summary>
        /// The <see cref="NoCoverVisible" /> property's name.
        /// </summary>
        public const string NoCoverVisiblePropertyName = "NoCoverVisible";

        private Visibility _noCoverVisible = Visibility.Visible;

        /// <summary>
        /// Gets the NoCoverVisible property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public Visibility NoCoverVisible
        {
            get
            {
                return _noCoverVisible;
            }

            set
            {
                this.SetPropertyAndNotify(ref _noCoverVisible, value, NoCoverVisiblePropertyName);
            }
        }
        #endregion

        #region MovieUserStats
        /// <summary>
        /// The <see cref="MovieUserStats" /> property's name.
        /// </summary>
        public const string MovieUserStatsPropertyName = "MovieUserStats";

        private MovieUserStats _movieUserStats = null;

        /// <summary>
        /// Gets the MovieUserStats property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public MovieUserStats MovieUserStats
        {
            get
            {
                return _movieUserStats;
            }

            set
            {
                this.SetPropertyAndNotify(ref _movieUserStats, value, MovieUserStatsPropertyName);
            }
        }
        #endregion
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the MovieSummaryViewModel class.
        /// </summary>
        public MovieSummaryViewModel(INavigationService navigationService, IStorageService storageService, IStoreSettings settingsService, IMessenger messenger)
            : base(navigationService, storageService, settingsService, messenger)
        {
            //Use of the Coding 4 Fun PhoneHelper to get the application title from the configuration
            this.ApplicationTitle = PhoneHelper.GetAppAttribute("Title").ToUpper();
            this.MessengerInstance.Register<SelectedMovieChangedMessage>(this, selectedMovie => this.GetMovieSummary(selectedMovie.MovieID));
            this.SaveHaveCommand = new RelayCommand(() => this.Save(SaveType.Have));
            this.SaveWatchedCommand = new RelayCommand(() => this.Save(SaveType.Watched));
            this.SaveRatingCommand = new RelayCommand(() => this.Save(SaveType.Rating));

            //TODO: Sync all http retrievals! Look at Cycling waypoints app!
        }
        #endregion

        #region Private methods
        private void Save(SaveType saveType)
        {
            this.ProgressIndicatorText = "Saving...";
            this.ProgressIndicatorVisible = true;

            switch (saveType)
            {
                case SaveType.Have:
                case SaveType.Watched:
                    JObject movieObject = new JObject(
                                                new JProperty("username", FollwItApi.GetInstance().UserName),
                                                new JProperty("password", FollwItApi.GetInstance().HashPassword(FollwItApi.GetInstance().Password)),
                                                new JProperty("movie_id", this.MovieSummary.MovieDetail.Movie_id)
                                          );

                    PostClient proxy = new PostClient(movieObject.ToString());
                    proxy.DownloadStringCompleted += (sender, e) =>
                    {
                        try
                        {
                            if (e.Error == null)
                            {
                                if (!e.Result.Contains("success"))
                                    throw new MovieSummaryException(string.Concat("Error while saving Movie Summary stats", Environment.NewLine, "Reason: ", e.Result));
                            }
                            else
                            {
                                throw new FollwitException("Error while saving Movie Summary stats", e.Error);
                            }
                        }
                        finally
                        {
                            this.ProgressIndicatorVisible = false;
                        }
                    };

                    if (saveType == SaveType.Have)
                    {
                        if (this.MovieUserStats.In_collection)
                            proxy.DownloadStringAsync(new Uri(FollwItApi.GetInstance().GetActionRestURI(RestAction.PostMovieCollection), UriKind.Absolute));
                        else
                            proxy.DownloadStringAsync(new Uri(FollwItApi.GetInstance().GetActionRestURI(RestAction.PostMovieUncollection), UriKind.Absolute));
                    }

                    if (saveType == SaveType.Watched)
                    {
                        if (this.MovieUserStats.Watched)
                            proxy.DownloadStringAsync(new Uri(FollwItApi.GetInstance().GetActionRestURI(RestAction.PostMovieWatched), UriKind.Absolute));
                        else
                            proxy.DownloadStringAsync(new Uri(FollwItApi.GetInstance().GetActionRestURI(RestAction.PostMovieUnwatched), UriKind.Absolute));
                    }
                    break;
                case SaveType.Rating:
                    JObject movieRateObject = new JObject(
                                                    new JProperty("username", FollwItApi.GetInstance().UserName),
                                                    new JProperty("password", FollwItApi.GetInstance().HashPassword(FollwItApi.GetInstance().Password)),
                                                    new JProperty("movie_id", this.MovieSummary.MovieDetail.Movie_id),
                                                    new JProperty("rating", this.MovieUserStats.Rating)
                                              );

                    PostClient proxyRate = new PostClient(movieRateObject.ToString());
                    proxyRate.DownloadStringCompleted += (sender, e) =>
                    {
                        try
                        {
                            if (e.Error == null)
                            {
                                if (!e.Result.Contains("success"))
                                    throw new MovieSummaryException(string.Concat("Error while saving Movie Rating stats", Environment.NewLine, "Reason: ", e.Result));
                            }
                            else
                            {
                                throw new FollwitException("Error while saving Movie Rating stats", e.Error);
                            }
                        }
                        finally
                        {
                            this.ProgressIndicatorVisible = false;
                        }
                    };

                    proxyRate.DownloadStringAsync(new Uri(FollwItApi.GetInstance().GetActionRestURI(RestAction.PostMovieRate), UriKind.Absolute));
                    break;
                default:
                    break;
            }
        }

        private void GetMovieSummary(int movieID)
        {
            this.ProgressIndicatorText = "Retrieving details...";
            this.ProgressIndicatorVisible = true;

            this.GetMovieUserStats(movieID);

            //Clear previous title
            this.ApplicationTitle = PhoneHelper.GetAppAttribute("Title").ToUpper();
            this.NoCoverVisible = Visibility.Visible;
            this.CoverVisible = Visibility.Collapsed;

            //First get the movie summary
            DataManager.Current.Load<agfxMovieSummaryViewModel>(movieID, (vm) =>
            {
                this.MovieSummary = vm;
                this.CoverVisible = Visibility.Visible;
                this.NoCoverVisible = Visibility.Collapsed;
                this.ProgressIndicatorVisible = false;
            },
            (ex) =>
            {
                this.ProgressIndicatorVisible = false;
                throw new FollwitException("Error while loading Movie Summary", ex);
            });

            //this.ProgressIndicatorVisible = true;
            ////Secondly get the default user referenced info for this movie
            //DataManager.Current.Load<agfxMovieCollectionViewModel>(FollwItApi.GetInstance().UserName, (vm) =>
            //{
            //    this.MovieCollection = vm;

            //    //Set the toggle buttons
            //    var movieInCollection = (from Movie movie in this.MovieCollection.Movies
            //                             where movie.MovieID == movieID
            //                             select movie).FirstOrDefault();

            //    this.ToggleOwn = !ReferenceEquals(movieInCollection, null);

            //    this.ProgressIndicatorVisible = false;
            //},
            //(ex) =>
            //{
            //    this.ProgressIndicatorVisible = false;            
            //});
        }

        /// <summary>
        /// Get the movie statistics for a given username
        /// </summary>
        /// <param name="movieID"></param>
        /// <param name="queryUserName"></param>
        /// <returns></returns>
        private void GetMovieUserStats(int movieID, string queryUserName = "")
        {
            this.ProgressIndicatorVisible = true;
            if (string.IsNullOrEmpty(queryUserName))
                queryUserName = FollwItApi.GetInstance().UserName;

            JObject o = new JObject(
                            new JProperty("username", FollwItApi.GetInstance().UserName),
                            new JProperty("password", FollwItApi.GetInstance().HashPassword(FollwItApi.GetInstance().Password)),
                            new JProperty("movie_id", movieID),
                            new JProperty("query_username", queryUserName)
                            );

            //new JProperty("movies",
            //    new JArray(
            //            new JObject(new JProperty("resources", "movie_id=5"), new JProperty("in_collection", false))
            //        )
            //    )

            PostClient proxy = new PostClient(o.ToString());
            proxy.DownloadStringCompleted += (sender, e) =>
            {
                try
                {
                    if (e.Error == null)
                    {
                        this.ProcessResponse(e.Result);
                    }
                    else
                    {
                        throw new FollwitException("Error while retrieving the user statistics", e.Error);
                    }
                }
                finally
                {
                    this.ProgressIndicatorVisible = false;
                }
            };

            proxy.DownloadStringAsync(new Uri(FollwItApi.GetInstance().GetActionRestURI(RestAction.PostMovieUserstats), UriKind.Absolute));
        }

        private void ProcessResponse(string result)
        {
            JObject movieUserStatsJSon = JObject.Parse(result);
            JsonSerializer serializer = new JsonSerializer();
            this.MovieUserStats = (MovieUserStats)serializer.Deserialize(new JTokenReader(movieUserStatsJSon), typeof(MovieUserStats));
        }
        #endregion

        #region ViewModelBaseWp7 implementation
        protected override void IsBeingActivated(WP7Contrib.Services.Storage.IStorage storage)
        {
            this.MessengerInstance.Send<SelectedMovieChangedMessage>(new SelectedMovieChangedMessage(storage.Read<int>("MovieID")));
        }

        protected override void IsBeingDeactivated(WP7Contrib.Services.Storage.IStorage storage)
        {
            storage.Write<int>("MovieID", int.Parse(_movieSummary.MovieDetail.Movie_id));
        }
        #endregion
    }
}